package mediator;

import guiWindows.GUIShowProperty;
import guiWindows.MainWindow;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.LinkedList;
import java.util.Set;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;

import objectsDiagram.Condition;
import objectsDiagram.Flow;
import objectsDiagram.State;
import objectsDiagram.Task;

import lts.Analyser;
import lts.CompositeState;
import lts.LTSOutput;
import main.LTSA;

public class ShowPropertyMediator implements ActionListener, LTSOutput, ItemListener  {
	private static final String TRACE_OUTPUTCONDITION = "outputcondition";
	private GUIShowProperty guiShowProperty;
	private LTSA ltsa;
	private MainWindow mainWindow;
	private Vector<Task> vectorTasks;
	private Vector<Flow> vectorFlows;
	private Vector<Condition> vectorConditions;
	private LinkedList<State> listConditionSource;
	private LinkedList<State> listConditionTarget;
	private String currentDefinitionByButton;

	public ShowPropertyMediator(LTSA ltsa){
		this.ltsa = ltsa;
		this.initialize();
	}

	private void initialize() {
		this.listConditionSource = new LinkedList<State>();
		this.listConditionTarget = new LinkedList<State>();
		this.guiShowProperty = new GUIShowProperty();
		this.guiShowProperty.getButtonTrace().setEnabled(false);
		this.guiShowProperty.setListenerButtons(this);
		this.guiShowProperty.setListModules(ltsa.getArrayModules());
		this.loadAssertions();
	}

	private void loadAssertions() {
		for(int i = ltsa.getDefinitionArray().length-1;i>=0;i--){
			this.guiShowProperty.addButtonToBox((String)ltsa.getDefinitionArray()[i], this);	
		}
	}

	public void showUp() {
		this.guiShowProperty.setVisible(true);
	}

	public void actionPerformed(ActionEvent e) {
		if(this.guiShowProperty.getButtonClose() == e.getSource()){
			this.guiShowProperty.setVisible(false);
			this.mainWindow.getGuiCreateProperties().getAddButton().setVisible(true);
			this.mainWindow.getGuiCreateProperties().getDeleteButton().setVisible(true);
			this.mainWindow.getGuiCreateProperties().getCheckPropertyButton().setVisible(true);
			this.mainWindow.getGuiCreateProperties().getBackButton().setVisible(false);
			this.guiShowProperty.dispose();
		}
		for(int i = 0;i<this.guiShowProperty.getVerticalsButtons().getComponentCount();i++){
			JButton currentButton = (JButton)this.guiShowProperty.getVerticalsButtons().getComponent(i);
			if(currentButton == e.getSource()){
				currentDefinitionByButton = currentButton.getText();
				clearOutput();
				CompositeState csModule = ltsa.docompile((String)this.guiShowProperty.getListModules().getSelectedItem());
				CompositeState csProperty = ltsa.runDefinition(currentButton.getText(),this);
				//Analyser a = new Analyser(cs,this,null);
				//a.analyse(cs.getFluentTracer());
				//System.out.println((String)ltsa.getArrayModules().get(0));
				//ltsa.compile((String)ltsa.getArrayModules().get(0));
				csModule.checkLTL(this, csProperty);
				String currentString = this.guiShowProperty.getResultEditorArea().getText();
				if(currentString.contains(ConstantsModel.TRACE_STRING) || currentString.contains(ConstantsModel.TRACE_STRING_1)){
					this.guiShowProperty.getButtonTrace().setText("TRACE");
					this.guiShowProperty.getButtonTrace().setEnabled(true);
				}else{
					this.guiShowProperty.getButtonTrace().setText("RESULT");
					this.guiShowProperty.getButtonTrace().setEnabled(true);
				}
			}
		}
		if(this.guiShowProperty.getButtonTrace() == e.getSource()){
			if(this.guiShowProperty.getButtonTrace().getText().equals("RESULT")){
				this.mainWindow.getGuiCreateProperties().getAddButton().setVisible(false);
				this.mainWindow.getGuiCreateProperties().getDeleteButton().setVisible(false);
				this.mainWindow.getGuiCreateProperties().getCheckPropertyButton().setVisible(false);
				this.mainWindow.getGuiCreateProperties().getBackButton().setVisible(true);
				for(int i= 0; i< ltsa.getDefinitionArray().length ; i++){
					if(ltsa.getDefinitionArray()[i].equals(currentDefinitionByButton)){
						this.mainWindow.getGuiCreateProperties().getListPanelAreas().get(i).getArea().setBackground(new Color(147, 254, 158));
						this.mainWindow.getGuiCreateProperties().getListPanelAreas().get(i).getArea().repaint();
					}
				}
				this.mainWindow.setTrace(null);
				this.guiShowProperty.setVisible(false);
			}else{
				listConditionSource.clear();
				listConditionTarget.clear();
				String currentString = this.guiShowProperty.getResultEditorArea().getText();
				String trace = ConstantsModel.TRACE_STRING;
				String traceEnds = ConstantsModel.END_TRACE_STRING;
				String currentStateString = "";
				LinkedList<String> listStates = new LinkedList<String>();
				LinkedList<String> traceList = new LinkedList<String>();
				BufferedReader reader = new BufferedReader(new StringReader(currentString));
				try {
					while((currentStateString = reader.readLine()) != null && !(currentStateString.equals(trace) || currentStateString.contains(ConstantsModel.TRACE_STRING_1)) );
					while((currentStateString = reader.readLine()) != null && (!currentStateString.equals(traceEnds)|| currentStateString.startsWith("_"))){
						if(!currentStateString.contains(TRACE_OUTPUTCONDITION)){
							listStates.addLast(currentStateString);
						}
					}
					for(String stateString : listStates ){
						String realState = retrieveCorrectState(stateString, vectorTasks);
						if(!traceList.contains(realState)){
							traceList.add(realState);
						}
					}
				} catch (IOException e1) {
					e1.printStackTrace();
				}
				String sourceString = "";
				LinkedList<State> listStateTrace = new LinkedList<State>();
				LinkedList<Flow> listFlowTrace = new LinkedList<Flow>();
				Object[] arrayTrace = new Object[2];
				for(int i=0;i<traceList.size();i++){
					String realState = traceList.get(i);
					Task retrivedTask = null;
					if(realState.contains(".")){
						String afterDotString = realState.substring(realState.indexOf(".")+1);
						retrivedTask = retrieveTask(afterDotString, vectorTasks);
					}else{
						retrivedTask = retrieveTask(realState, vectorTasks);
					}
					if(retrivedTask != null){
						completeWithConditions(retrivedTask,listFlowTrace);
						listStateTrace.add(retrivedTask);
					}
				}
				listStateTrace.addAll(intersect(listConditionSource, listConditionTarget));
				completeWithFlows(listStateTrace, listFlowTrace);
				arrayTrace[0] = listStateTrace;
				arrayTrace[1] = listFlowTrace;
				for(State condition : listStateTrace){
					condition.setColor(Color.BLUE);
					condition.setInTrace(true);
				}
				this.mainWindow.getGuiCreateProperties().getAddButton().setVisible(false);
				this.mainWindow.getGuiCreateProperties().getDeleteButton().setVisible(false);
				this.mainWindow.getGuiCreateProperties().getCheckPropertyButton().setVisible(false);
				this.mainWindow.getGuiCreateProperties().getBackButton().setVisible(true);
				this.mainWindow.setTrace(arrayTrace);
				for(int i= 0; i< ltsa.getDefinitionArray().length ; i++){
					if(ltsa.getDefinitionArray()[i].equals(currentDefinitionByButton)){
						this.mainWindow.getGuiCreateProperties().getListPanelAreas().get(i).getArea().setBackground(new Color(254, 147, 149));
						this.mainWindow.getGuiCreateProperties().getListPanelAreas().get(i).getArea().repaint();
					}
				}
				this.mainWindow.repaintDiagrams();
				this.guiShowProperty.setVisible(false);
			}
		}
	}

	public void clearOutput() {
		this.guiShowProperty.getResultEditorArea().setText(" ");
	}

	public void out(String str) {
		String currentString = this.guiShowProperty.getResultEditorArea().getText();
		currentString = (currentString+str);
		this.guiShowProperty.getResultEditorArea().setText(currentString);
	}

	public void outln(String str) {
		if (str.contains(ConstantsModel.TRACE_STRING) || str.contains(ConstantsModel.TRACE_STRING_1))
			appendToPane(str+"\n", Color.RED, true);
		else
			appendToPane(str+"\n", Color.BLACK, false);
	}

	@Override
	public void itemStateChanged(ItemEvent e) {
	}


	private void appendToPane(String msg, Color c, boolean b)
	{
		StyleContext sc = StyleContext.getDefaultStyleContext();
		AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, c);

		aset = sc.addAttribute(aset, StyleConstants.Bold, b);

		this.guiShowProperty.getResultEditorArea().setCharacterAttributes(aset, false);
		this.guiShowProperty.getResultEditorArea().replaceSelection(msg);
	}

	private String retrieveCorrectState(String sourceString, Vector<Task> vectorTask){
		String currentStateString = "";
		if(sourceString.contains(".")){//Multiple Task
			String beforeDotString = sourceString.substring(0,sourceString.indexOf("."));
			String afterDotString = sourceString.substring(sourceString.indexOf(".")+1);
			return retrieveCorrectState(beforeDotString, vectorTask)+"."+retrieveCorrectState(afterDotString, vectorTask) ;
		}
		else{
			for(Task currentTask:vectorTask){//Simple Task
				if(sourceString.contains(currentTask.getId().toLowerCase())){
					if(currentStateString.length() < currentTask.getId().toLowerCase().length()){
						currentStateString = currentTask.getId().toLowerCase();
					}
				}
			}
		}
		return currentStateString;
	}

	private Task retrieveTask(String sourceString, Vector<Task> vectorTask){
		Task foundTask = null;
		for(Task currentTask : vectorTask){
			if(sourceString.equals(currentTask.getId().toLowerCase())){
				foundTask = currentTask;
			}
		}
		return foundTask;
	}

	public void setMainWindow(MainWindow newMainWindow) {
		this.mainWindow = newMainWindow;
	}

	public GUIShowProperty getGUIShowProperty(){
		return this.guiShowProperty;
	}

	public void setVectorTask(Vector<Task> vectorTasks) {
		this.vectorTasks = vectorTasks;
	}
	public void setVectorCondition(Vector<Condition> vectorConditions) {
		this.vectorConditions = vectorConditions;
	}
	public void setVectorFlow(Vector<Flow> vectorFlows) {
		this.vectorFlows = vectorFlows;
	}

	private void completeWithConditions(Task retrivedTask, LinkedList<Flow> listFlowTrace) {
		for(Flow currentFlow : vectorFlows){
			if(currentFlow.getTarget().getId().equals(retrivedTask.getId())){
				for(Condition currentCondition : vectorConditions){
					if(currentFlow.getSource().getId().equals(currentCondition.getId())){
						listConditionSource.add(currentFlow.getSource());
					}
				}
			}else if(currentFlow.getSource().getId().equals(retrivedTask.getId())){
				for(Condition currentCondition : vectorConditions){
					if(currentFlow.getTarget().getId().equals(currentCondition.getId())){
						listConditionTarget.add(currentFlow.getTarget());
					}
				}
			}
		}
	}

	private void completeWithFlows(LinkedList<State> listStateTrace, LinkedList<Flow> listFlowTrace) {
		for(Flow currentFlow : vectorFlows){
			for(State currentSourceState : listStateTrace){
				if(currentFlow.getSource().getId().equals(currentSourceState.getId())){
					for(State currentTargetState : listStateTrace){
						if(currentFlow.getTarget().getId().equals(currentTargetState.getId())){
							currentFlow.setColor(Color.BLUE);
							currentFlow.setInTrace(true);
							listFlowTrace.add(currentFlow);
						}
					}
				}
			}
		}
	}

	private LinkedList<State> intersect(LinkedList<State> A, LinkedList<State> B) {
		LinkedList<State> rtnList = new LinkedList<State>();
		for(State dtoA : A) {
			for(State dtoB : B){
				if(dtoA.getId().equals(dtoB.getId())){
					rtnList.add(dtoA);
				}
			}
		}
		return rtnList;
	}
}
